<template>
  <div style="width: 100%; height: 100%; position: relative">
    <div id="container"></div>
    <div id="tooltip"></div>
  </div>
</template>

<script setup>
import * as THREE from 'three';
import * as d3 from 'd3';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';

import { getCurrentInstance, ref, watch } from 'vue';
const { proxy } = getCurrentInstance();
const props = defineProps({
  dataAlarm: {
    type: Array,
    default: () => []
  }
});
let camera = null;
let scene = null;
let renderer = null;
let labelRenderer = null;
let container = null;
let controller = null;
let map = null;
let raycaster = null;
let mouse = null;
let tooltip = null;
let lastPick = null;
let groupTwo = new THREE.Group();
let alarmWaveMeshArr = [];
let alarmCylinderMeshArr = [];
let alarmNameMeshArr = [];
let mapEdgeLightObj = {
  mapEdgePoints: [],
  // 单独把geometry提出来，动画用
  lightOpacityGeometry: null,
  // 边缘流光参数
  lightSpeed: 3,
  lightCurrentPos: 0,
  lightOpacitys: null
};
let mapConfig = {
  deep: 0.2
};
const dataAlarmList = ref(props.dataAlarm);
let cameraPosArr = [
  // {x: 0.0, y: -0.3, z: 1},
  // {x: 5.0, y: 5.0, z: 2},
  // {x: 3.0, y: 3.0, z: 2},
  // {x: 0, y: 5.0, z: 2},
  // {x: -2.0, y: 3.0, z: 1},
  { x: 0, y: -3.0, z: 3.8 }
];
watch(
  () => props.dataAlarm,
  (newValue, oldValue) => {
    // 注意：`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
    dataAlarmList.value = newValue;
    init();
    animate();
    window.addEventListener('resize', onWindowSize);
  },
  { deep: true }
);
//初始化
function init() {
  container = document.getElementById('container');

  setScene();
  setCamera();
  setRenderer(); // 创建渲染器对象
  setController(); // 创建控件对象
  addHelper();
  loadMapData();
  setEarth();
  setRaycaster();
  setLight();
}

function setScene() {
  //  创建场景对象Scene
  scene = new THREE.Scene();
}

function setCamera() {
  // 第二参数就是 长度和宽度比 默认采用浏览器  返回以像素为单位的窗口的内部宽度和高度
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 500);
  // 0, -5, 1
  camera.position.set(0, -5, 1);
  // 0, 0, 0 this.scene.position
  camera.lookAt(new THREE.Vector3(0, 0, 0));
}

function setRenderer() {
  renderer = new THREE.WebGLRenderer({
    antialias: true
    // logarithmicDepthBuffer: true,  // 是否使用对数深度缓存
  });
  renderer.setSize(container.clientWidth, container.clientHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  // this.renderer.sortObjects = false;  // 是否需要对对象排序
  container.appendChild(renderer.domElement);

  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(container.clientWidth, container.clientHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = 0;
  container.appendChild(labelRenderer.domElement);
}

function setController() {
  controller = new OrbitControls(camera, labelRenderer.domElement);
  controller.minDistance = 2;
  controller.maxDistance = 5.5; // 5.5

  // 阻尼（惯性）
  // this.controller.enableDamping = true;
  // this.controller.dampingFactor = 0.04;

  controller.minAzimuthAngle = -Math.PI / 4;
  controller.maxAzimuthAngle = Math.PI / 4;

  controller.minPolarAngle = 1;
  controller.maxPolarAngle = Math.PI - 0.1;

  // 修改相机的lookAt是不会影响THREE.OrbitControls的target的
  // this.controller.target = new THREE.Vector3(0, -5, 2);
}

// 辅助线
function addHelper() {
  // let helper = new THREE.CameraHelper(this.camera);
  // this.scene.add(helper);

  //轴辅助 （每一个轴的长度）
  // eslint-disable-next-line no-unused-vars
  let axisHelper = new THREE.AxisHelper(150); // 红线是X轴，绿线是Y轴，蓝线是Z轴
  // this.scene.add(axisHelper);

  // eslint-disable-next-line no-unused-vars
  let gridHelper = new THREE.GridHelper(100, 30, 0x2c2c2c, 0x888888);
  // this.scene.add(gridHelper);
}

function setLight() {
  let ambientLight = new THREE.AmbientLight(0x404040, 1.2);
  scene.add(ambientLight);
  // // 平行光
  let directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
  scene.add(directionalLight);

  // 点光源 - 照模型
  let test = new THREE.PointLight('#ffffff', 1.8, 20);
  test.position.set(1, -7, 7);
  scene.add(test);
  let testHelperMap = new THREE.PointLightHelper(test);
  scene.add(testHelperMap);

  // 点光源 - 蓝色照地球
  let pointLightMap = new THREE.PointLight('#4161ff', 1.4, 20);
  pointLightMap.position.set(0, 7, 3);
  scene.add(pointLightMap);
}

// 加载地图数据
function loadMapData() {
  let loader = new THREE.FileLoader();
  loader.load('/static/map/json/hebei.json', data => {
    const jsondata = JSON.parse(data);
    addMapGeometry(jsondata);
  });
}

// 地图模型
function addMapGeometry(jsondata) {
  // 初始化一个地图对象
  map = new THREE.Object3D();
  // 墨卡托投影转换
  const projection = d3
    .geoMercator()
    .center([115.702461, 38.745474]) // 石家庄市
    .scale(40)
    .translate([0.2, 0.15]); // 根据地球贴图做轻微调整

  jsondata.features.forEach(elem => {
    // 定一个省份3D对象
    const province = new THREE.Object3D();
    // 每个的 坐标 数组
    const coordinates = elem.geometry.coordinates;
    // 循环坐标数组
    coordinates.forEach(multiPolygon => {
      multiPolygon.forEach(polygon => {
        const shape = new THREE.Shape();
        const lineMaterial = new THREE.LineBasicMaterial({
          color: '#ffffff'
          // linewidth: 1,
          // linecap: 'round', //ignored by WebGLRenderer
          // linejoin:  'round' //ignored by WebGLRenderer
        });
        // const lineGeometry = new THREE.Geometry();
        // for (let i = 0; i < polygon.length; i++) {
        //   const [x, y] = projection(polygon[i]);
        //   if (i === 0) {
        //     shape.moveTo(x, -y);
        //   }
        //   shape.lineTo(x, -y);
        //   lineGeometry.vertices.push(new THREE.Vector3(x, -y, 3));
        // }
        const lineGeometry = new THREE.BufferGeometry();
        const pointsArray = new Array();
        for (let i = 0; i < polygon.length; i++) {
          const [x, y] = projection(polygon[i]);
          if (i === 0) {
            shape.moveTo(x, -y);
          }
          shape.lineTo(x, -y);
          pointsArray.push(new THREE.Vector3(x, -y, mapConfig.deep));

          // 做边缘流光效果，把所有点保存下来
          mapEdgeLightObj.mapEdgePoints.push([x, -y, mapConfig.deep]);
        }
        // console.log(pointsArray);
        lineGeometry.setFromPoints(pointsArray);

        const extrudeSettings = {
          depth: mapConfig.deep,
          bevelEnabled: false // 对挤出的形状应用是否斜角
        };
        //地图上面的颜色
        const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
        const material = new THREE.MeshPhongMaterial({
          color: '#08afdf',
          transparent: true,
          opacity: 0.6,
          side: THREE.FrontSide
          // depthTest: true,
        });
        //地图侧边的颜色
        const material1 = new THREE.MeshLambertMaterial({
          color: '#10004a',
          transparent: true,
          opacity: 0.7,
          side: THREE.FrontSide
          // wireframe: true
        });
        const mesh = new THREE.Mesh(geometry, [material, material1]);
        const line = new THREE.Line(lineGeometry, lineMaterial);
        // 将省份的属性 加进来
        province.properties = elem.properties;

        // 将城市信息放到模型中，后续做动画用
        if (elem.properties.centroid) {
          const [x, y] = projection(elem.properties.centroid); // uv映射坐标
          province.properties._centroid = [x, y];
        }

        // console.log(elem.properties);
        province.add(mesh);
        province.add(line);
      });
    });
    // province.scale.set(5, 5, 0);
    // province.position.set(0, 0, 0);
    // console.log(province);
    map.add(province);
  });
  setMapEdgeLight();
  setMapName();
  scene.add(map);

  // 获取数据后，加载模型
  getResponseData();
}

// 地图边缘流光效果
function setMapEdgeLight() {
  // console.log(this.mapEdgeLightObj.mapEdgePoints);
  let positions = new Float32Array(mapEdgeLightObj.mapEdgePoints.flat(1)); // 数组深度遍历扁平化
  // console.log(positions);
  mapEdgeLightObj.lightOpacityGeometry = new THREE.BufferGeometry();
  // 设置顶点
  mapEdgeLightObj.lightOpacityGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  // 设置 粒子透明度为 0
  mapEdgeLightObj.lightOpacitys = new Float32Array(positions.length).map(() => 0);
  mapEdgeLightObj.lightOpacityGeometry.setAttribute('aOpacity', new THREE.BufferAttribute(mapEdgeLightObj.lightOpacitys, 1));

  // 顶点着色器
  const vertexShader = `
          attribute float aOpacity;
          uniform float uSize;
          varying float vOpacity;

          void main(){
              gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
              gl_PointSize = uSize;

              vOpacity=aOpacity;
          }
          `;
  // 片段着色器
  const fragmentShader = `
          varying float vOpacity;
          uniform vec3 uColor;

          float invert(float n){
              return 1.-n;
          }

          void main(){
            if(vOpacity <=0.2){
                discard;
            }
            vec2 uv=vec2(gl_PointCoord.x,invert(gl_PointCoord.y));
            vec2 cUv=2.*uv-1.;
            vec4 color=vec4(1./length(cUv));
            color*=vOpacity;
            color.rgb*=uColor;
            gl_FragColor=color;
          }
          `;

  const material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    transparent: true, // 设置透明
    // blending: THREE.AdditiveBlending,
    uniforms: {
      uSize: {
        value: 5.0
      },
      uColor: {
        value: new THREE.Color('#ffffff') // 光点颜色 fffb85
      }
    }
  });
  // material.blending = THREE.AdditiveBlending;
  const opacityPointsMesh = new THREE.Points(mapEdgeLightObj.lightOpacityGeometry, material);
  scene.add(opacityPointsMesh);
}
// 地球贴图纹理
function setEarth() {
  const geometry = new THREE.PlaneGeometry(25.0, 18.0);
  const texture = new THREE.TextureLoader().load('/static/map/texture/555.jpg');
  const bumpTexture = new THREE.TextureLoader().load('/static/map/texture/555.jpg');
  // texture.wrapS = THREE.RepeatWrapping;  // 质地.包裹
  // texture.wrapT = THREE.RepeatWrapping;

  const material = new THREE.MeshPhongMaterial({
    map: texture, // 贴图
    bumpMap: bumpTexture,
    bumpScale: 0.05,
    // specularMap: texture,
    // specular: 0xffffff,
    // shininess: 1,
    // color: "#000000",
    side: THREE.FrontSide
  });
  const earthPlane = new THREE.Mesh(geometry, material);
  scene.add(earthPlane);
}

// 射线
function setRaycaster() {
  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2();
  tooltip = document.getElementById('tooltip');
  const onMouseMove = event => {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    tooltip.style.left = event.clientX + 2 + 'px';
    tooltip.style.top = event.clientY + 2 + 'px';
  };

  // 点击地图事件
  // eslint-disable-next-line no-unused-vars
  const onClick = event => {
    // console.log(this.lastPick);
    if (lastPick && 'point' in lastPick) {
      mapClickTween(lastPick.point);
    } else {
      resetCameraTween();
    }
  };

  window.addEventListener('mousemove', onMouseMove, false);
  window.addEventListener('click', onClick, false);
}

// 获取数据后，加载模型
function getResponseData() {
  setTimeout(function () {
    addAlarmModel();
    // 初始化动画
    setTimeout(self.cameraTween, 1000);
  }, 500);
}

// 地图label
function setMapName() {
  map.children.forEach(elem => {
    // 找到中心点
    const y = -elem.properties._centroid[1];
    const x = elem.properties._centroid[0];
    // 转化为二维坐标
    const vector = new THREE.Vector3(x, y, mapConfig.deep + 0.01);
    // 添加城市名称
    setCityName(vector, elem.properties.name);
  });
}
// 城市 - 名称显示
function setCityName(vector, name) {
  let spritey = makeTextSprite(name, {
    fontface: '微软雅黑',
    fontsize: 28, // 定100调整位置，下面通过scale缩放
    fontColor: { r: 255, g: 255, b: 255, a: 1.0 },
    borderColor: { r: 94, g: 94, b: 94, a: 0.0 },
    backgroundColor: { r: 255, g: 255, b: 0, a: 0.0 },
    borderThickness: 2,
    round: 6
  });
  // 轻微偏移，错开光柱
  spritey.position.set(vector.x + 0.06, vector.y + 0.0, 0.22); // num + 0.3
  scene.add(spritey);
  // console.log('88888888888888', spritey);
}

// 城市 - 名称显示 - 小精灵mesh
function makeTextSprite(message, parameters) {
  if (parameters === undefined) parameters = {};

  let fontface = parameters['fontface'];
  let fontsize = parameters['fontsize'];
  let fontColor = parameters['fontColor'];
  let borderThickness = parameters['borderThickness'];
  let borderColor = parameters['borderColor'];
  let backgroundColor = parameters['backgroundColor'];

  // var spriteAlignment = THREE.SpriteAlignment.topLeft;

  let canvas = document.createElement('canvas');
  let context = canvas.getContext('2d');
  context.font = 'Bold ' + fontsize + 'px ' + fontface;

  // get size data (height depends only on font size)
  let metrics = context.measureText(message);
  let textWidth = metrics.width;

  // background color
  context.fillStyle = 'rgba(' + backgroundColor.r + ',' + backgroundColor.g + ',' + backgroundColor.b + ',' + backgroundColor.a + ')';
  // border color
  context.strokeStyle = 'rgba(' + borderColor.r + ',' + borderColor.g + ',' + borderColor.b + ',' + borderColor.a + ')';

  context.lineWidth = borderThickness;
  const painting = {
    width: textWidth * 1.4 + borderThickness * 2,
    height: fontsize * 1.4 + borderThickness * 2,
    round: parameters['round']
  };
  // 1.4 is extra height factor for text below baseline: g,j,p,q.
  // context.fillRect(0, 0, painting.width, painting.height)
  roundRect(context, borderThickness / 2, borderThickness / 2, painting.width, painting.height, painting.round);

  // text color
  context.fillStyle = 'rgba(' + fontColor.r + ',' + fontColor.g + ',' + fontColor.b + ',' + fontColor.a + ')';
  context.textAlign = 'center';
  context.textBaseline = 'middle';

  context.fillText(message, painting.width / 2, painting.height / 2);

  // canvas contents will be used for a texture
  let texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;
  let spriteMaterial = new THREE.SpriteMaterial({
    map: texture,
    useScreenCoordinates: false,
    depthTest: false // 解决精灵谍影问题
    // blending: THREE.AdditiveBlending,
    // transparent: true,
    // alignment: spriteAlignment
  });
  let sprite = new THREE.Sprite(spriteMaterial);
  sprite.scale.set(1, 1 / 2, 1);
  return sprite;
}

// 城市 - 名称显示 - 样式
function roundRect(ctx, x, y, w, h, r) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.quadraticCurveTo(x + w, y, x + w, y + r);
  ctx.lineTo(x + w, y + h - r);
  ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
  ctx.lineTo(x + r, y + h);
  ctx.quadraticCurveTo(x, y + h, x, y + h - r);
  ctx.lineTo(x, y + r);
  ctx.quadraticCurveTo(x, y, x + r, y);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
}

//添加模型
function addAlarmModel() {
  // 数据归一化
  map.children.forEach(elem => {
    // console.log(elem);
    // 满足数据条件 dataAlarm
    if (dataAlarmList.value) {
      const vector = mapElem2Centroid(elem);
      // 各等级颜色 1、2、3
      // const colorLevel = ['#ff1800', '#FF8A00', '#FAE52D']
      const colorLevel = '#FAE52D';
      dataAlarmList.value.forEach(d => {
        // 判断区县
        if (d.name === elem.properties.name) {
          // 添加告警光波
          setAlarmWave(vector, colorLevel);

          // 添加告警标记
          setAlarmCylinder(vector, colorLevel);

          // 添加告警名称
          setAlarmName(vector, colorLevel, d);
        }
      });

      // 先隐藏，通过按钮控制
      // this.groupTwo.visible = false
      scene.add(groupTwo);
    }
  });
  // 地区中心点 - 获取向量
  function mapElem2Centroid(elem) {
    // 找到中心点
    const y = -elem.properties._centroid[1];
    const x = elem.properties._centroid[0];
    // 转化为二维坐标
    const vector = new THREE.Vector3(x, y, mapConfig.deep + 0.01);
    return vector;
  }

  // 告警 - 光波
  function setAlarmWave(vector, color) {
    const geometry = new THREE.PlaneBufferGeometry(1, 1); //默认在XOY平面上
    const textureLoader = new THREE.TextureLoader(); // TextureLoader创建一个纹理加载器对象
    const texture = textureLoader.load('/static/map/texture/alarm.png');

    const material = new THREE.MeshBasicMaterial({
      color: color,
      map: texture,
      transparent: true, //使用背景透明的png贴图，注意开启透明计算
      opacity: 1.0,
      side: THREE.FrontSide,
      depthWrite: false, //禁止写入深度缓冲区数据
      blending: THREE.AdditiveBlending
    });

    let mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(vector.x, vector.y, vector.z);
    mesh.scale.set(0.4, 0.4, 0.4); // 设置mesh大小

    alarmWaveMeshArr.push(mesh);
    groupTwo.add(mesh);
  }

  // 告警 - 三角锥标记
  function setAlarmCylinder(vector, color) {
    const geometry = new THREE.CylinderGeometry(0.1, 0.0, 0.3, 3);
    let material = new THREE.MeshPhongMaterial({
      // ShaderMaterial
      color: color,
      side: THREE.FrontSide,
      // blending: THREE.AdditiveBlending,
      transparent: true,
      opacity: 0.8
    });

    const cylinder = new THREE.Mesh(geometry, material);
    cylinder.position.set(vector.x, vector.y, vector.z + 0.2);
    cylinder.rotateX(Math.PI / 2);
    cylinder.scale.set(1, 1, 1);

    alarmCylinderMeshArr.push(cylinder);
    groupTwo.add(cylinder);
  }

  // 告警 - 名称显示
  function setAlarmName(vector, color, data) {
    // CSS2DRenderer生成的标签直接就是挂在真实的DOM上，并非是Vue的虚拟DOM上
    const div = document.createElement('div');
    div.className = 'alarm-label';
    const row1 = document.createElement('div');
    row1.className = 'alarm-label-row';
    const icon = document.createElement('span');
    icon.className = 'alarm-label-icon';
    icon.textContent = '●';
    icon.style.color = color;
    row1.appendChild(icon);

    const text = document.createElement('span');
    text.className = 'alarm-label-text';
    text.textContent = `矿泉水:${data.kqs}`;
    row1.appendChild(text);
    div.appendChild(row1);
    const row2 = document.createElement('div');
    row2.className = 'alarm-label-row';

    const icon1 = document.createElement('span');
    icon1.className = 'alarm-label-icon';
    icon1.textContent = '●';
    icon1.style.color = color;
    row2.appendChild(icon1);

    const text1 = document.createElement('span');
    text1.className = 'alarm-label-text';
    text1.textContent = `地热井:${data.drj}`;
    row2.appendChild(text1);
    div.appendChild(row2);
    /* const contentDiv = document.createElement('div')
      contentDiv.className = 'alarm-label-content'
      contentDiv.innerHTML =
        '告警：' +
        data.content +
        '<br/>' +
        '企业：' +
        data.company +
        '<br/>' +
        '位置：' +
        data.location +
        '<br/>' +
        '电话：' +
        data.tel
      div.appendChild(contentDiv) */

    const label = new CSS2DObject(div);
    label.position.set(vector.x, vector.y, vector.z + 0.75);
    label.visible = true;
    alarmNameMeshArr.push(label);
    groupTwo.add(label);
    // this.scene.add(spritey);
  }
}
// Tween - 点击省份动画
function mapClickTween(pos) {
  //关闭控制器
  controller.enabled = false;

  const begin = {
    x: camera.position.x,
    y: camera.position.y,
    z: camera.position.z
  };
  const end = {
    x: pos.x,
    y: pos.y,
    z: pos.z + 2.5
  };
  proxy.$tween.use({
    begin,
    end,
    time: 500,
    onUpdate(obj) {
      camera.position.x = obj.x;
      camera.position.y = obj.y;
      camera.position.z = obj.z;

      camera.lookAt(obj.x, obj.y, obj.z);

      // 控制器更新
      controller.update();
    },
    onComplete() {
      controller.enabled = true;
    }
  });
}
// Tween - 重置相机
function resetCameraTween() {
  //关闭控制器
  controller.enabled = false;

  const begin = {
    x: camera.position.x,
    y: camera.position.y,
    z: camera.position.z
  };
  const end = {
    x: cameraPosArr[cameraPosArr.length - 1].x,
    y: cameraPosArr[cameraPosArr.length - 1].y,
    z: cameraPosArr[cameraPosArr.length - 1].z
  };

  proxy.$tween.use({
    begin,
    end,
    time: 500,
    onUpdate(obj) {
      camera.position.y = obj.y;
      camera.position.z = obj.z;
      camera.position.x = obj.x;

      camera.lookAt(0, 0, 0);

      // 控制器更新
      controller.update();
    },
    onComplete() {
      controller.enabled = true;
    }
  });
}
// 动画
function animate() {
  requestAnimationFrame(animate);

  showTip();
  animationMouseover();

  // alarm
  animationAlarmWave();
  animationAlarmCylinder();

  controller.update();
  renderer.render(scene, camera);
  labelRenderer.render(scene, camera);
}

// 鼠标悬浮显示
function showTip() {
  // 显示省份的信息
  if (lastPick) {
    const properties = lastPick.object.parent.properties;

    tooltip.textContent = properties.name;

    tooltip.style.visibility = 'visible';
  } else {
    tooltip.style.visibility = 'hidden';
  }
}

// 动画 - 鼠标悬浮动作
function animationMouseover() {
  // // 通过摄像机和鼠标位置更新射线
  raycaster.setFromCamera(mouse, camera);
  // 计算物体和射线的焦点，与当场景相交的对象有那些
  const intersects = raycaster.intersectObjects(
    scene.children,
    true // true，则同时也会检测所有物体的后代
  );
  // 恢复上一次清空的
  if (lastPick) {
    //移入时改变的颜色
    lastPick.object.material[0].color.set('#08afdf');
    // this.lastPick.object.material[1].color.set('#00035d');
  }
  lastPick = null;
  lastPick = intersects.find(
    item => item.object.material && item.object.material.length === 2 // 选择map object
  );
  if (lastPick) {
    //移入时的颜色
    lastPick.object.material[0].color.set('#00035d');
    lastPick.object.material[1].color.set('#00035d');
  }
}
// 动画 - 告警光波
function animationAlarmWave() {
  alarmWaveMeshArr.forEach(mesh => {
    mesh.rotation.z -= 0.01;
  });
}

// 动画 - 告警三角锥
function animationAlarmCylinder() {
  alarmCylinderMeshArr.forEach(mesh => {
    mesh.rotation.y += 0.03;
  });
}

// 窗口变化
function onWindowSize() {
  // let container = document.getElementById("container");
  camera.aspect = container.clientWidth / container.clientHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(container.clientWidth, container.clientHeight);
  labelRenderer.setSize(container.clientWidth, container.clientHeight);
}
</script>

<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}
#tooltip {
  position: absolute;
  z-index: 2;
  background: linear-gradient(180deg, #b0deff 0%, #2c4fdc 100%);
  padding: 6px 10px;
  color: #fff;
  border: 2px solid #fae52d;
  font-weight: bold;
  font-size: 16px;
  /* border-radius: 4px; */
  visibility: hidden;
}
#cityName {
  z-index: 2;
}
.button-group {
  position: absolute;
  left: 24px;
  top: 24px;
  z-index: 2;
}
.alarm-label-row {
  display: flex;
  align-items: center;
  padding-left: 5px;
}
/* 城市统计数据 */
.city-num-label {
  width: 32px;
  height: 32px;
  line-height: 32px;
  font-size: 16px;
  font-weight: bold;
  color: #ffffff;
  border-radius: 100px;
  background-color: rgba(192, 174, 12, 0.8);
  box-shadow: 0px 0px 4px rgba(237, 230, 25, 0.5);
  border: 2px solid rgba(237, 230, 25, 1);
  /* font-family: 'PingFang SC'; */
  text-align: center;
  cursor: pointer;
  /* opacity: 0.8; */
  transition: all 0.1s linear;
}
.city-num-label:hover {
  margin-top: -60px;
  width: 300px;
  min-height: 140px;
  padding: 16px 16px;
  text-align: left;
  /* opacity: 1.0; */
  border-radius: 4px;
  box-shadow: 0px 0px 12px rgba(237, 230, 25, 0.9);
}
.city-num-label-content {
  display: none;
  font-size: 12px;
  line-height: 24px;
  color: #eeeeee;
}
.city-num-label:hover .city-num-label-content {
  display: block;
}
/* 告警名称 */
.alarm-label {
  min-width: 100px;
  height: 64px;
  line-height: 30px;
  border-radius: 4px;
  background: rgba(10, 26, 52, 0.8);
  border: 1px solid #59aff9;
  box-shadow: 0px 0px 4px rgba(3, 149, 255, 0.5);
  text-align: center;
  cursor: pointer;
  transition: all 0.1s linear;
}
/* .alarm-label:hover {
  margin-top: -60px;
  width: 300px;
  min-height: 140px;
  padding: 16px 16px;
  text-align: left;
  opacity: 1.0;
  box-shadow: 0px 0px 12px rgba(3, 149, 255, 0.9);
} */
.alarm-label-icon {
  margin-right: 4px;
  font-size: 22px;
}
.alarm-label-text {
  font-size: 16px;
  font-weight: bold;
  color: #ffffff;
}
.alarm-label-content {
  display: none;
  font-size: 12px;
  line-height: 24px;
  color: #eeeeee;
}
/* .alarm-label:hover .alarm-label-content {
  display: block;
} */
</style>
